﻿using com.yoozoo.gta.Gameplay.PVE;
using DestroyIt;
using System;
using System.Collections.Generic;
using Gameplay.PVE.Survivor;
using UnityEditor.Rendering.Universal;
using UnityEngine;
using UnityEngine.Rendering;
using XLua;
using Yoozoo.Core.Extensions.CSharp;
using Yoozoo.Gameplay.Liberty;
using Yoozoo.Gameplay.Liberty.AI;

namespace Gameplay.PVE
{
    [System.Serializable]
    public class SceneObjectInfo : ISceneObject
    {
        #region 序列化部分
        [SerializeField]
        private Bounds m_Bounds;
        [SerializeField] 
        private int m_PrefabPathIndex;
        public int PrefabPathIndex => m_PrefabPathIndex;
        [SerializeField]
        private Vector3 m_Position;
        public Vector3 Position => m_Position;
        [SerializeField]
        private Vector3 m_Rotation;
        public Vector3 Rotation => m_Rotation;
        [SerializeField]
        private Vector3 m_Size;
        public Vector3 Size => m_Size;
        [SerializeField]
        private int m_Index;
        [SerializeField]
        private int m_MeshRendererDataStartIndex;
        [SerializeField]
        private int m_MeshRendererDataCount;
        [SerializeField]
        private bool m_IsStatic;
        [SerializeField]
        private SceneObjType m_SceneObjType;
        public SceneObjType SceneObjType => m_SceneObjType;
        public bool IsStatic => m_IsStatic;
        public Bounds Bounds => m_Bounds;
        public int Index => m_Index;

        [SerializeField] public bool IsNavmeshObject;
        [SerializeField] public Vector4 navmeshRegion;
        
        public Action<SceneObjectInfo> beforeShow;
        public Action<SceneObjectInfo,GameObject> afterShow;
        public Action<SceneObjectInfo> onHide;
        
        public SceneObjectInfo(Bounds bounds, Transform trans, int index, int prefabPathIndex, int startIndex, int count, bool isStatic, SceneObjType sceneObjType)
        {
            m_Bounds = bounds;
            m_Position = trans.position;
            m_Rotation = trans.eulerAngles;
            m_Size = trans.lossyScale;
            m_Index = index;
            m_PrefabPathIndex = prefabPathIndex;
            m_MeshRendererDataStartIndex = startIndex;
            m_MeshRendererDataCount = count;
            m_IsStatic = isStatic;
            m_SceneObjType = sceneObjType;
        }
        #endregion

        #region ISceneObject部分

        private GameObject m_LoadedPrefab;

        public GameObject LoadedPrefab => m_LoadedPrefab;

        private SceneSeparateManagerData data;
        private PrefabMeshRenderCache m_meshRenderCache;

        public void SetSceneSeparateManagerData(SceneSeparateManagerData data)
        {
            this.data = data;
        }

        public string GetPrefabPath()
        {
            return data.PrefabRootPath + data.PrefabPaths[PrefabPathIndex];
        }

        public void OnHide()
        {
            IsHide = true;
            if (m_LoadedPrefab)
            {
                // var rigidBody = m_LoadedPrefab.GetComponent<Rigidbody>();
                // if (rigidBody!=null)
                // {
                //     rigidBody.isKinematic = true;
                // }
                var destructibleList = LibertySceneManager.instance.GetComponentCachList;
                m_LoadedPrefab.GetComponentsInChildren<Destructible>(true, destructibleList);
                if (destructibleList != null)
                {
                    foreach (var destructible in destructibleList)
                    {
                        destructible.enabled = false;
                        destructible.OnDelete();
                    }
                }

                ResObjectCacheManager.UnLoad(GetPrefabPath(), m_LoadedPrefab);
                m_LoadedPrefab = null;
            }
            onHide?.Invoke(this);
        }

        public void AddLightmapIndices()
        {
            if (m_meshRenderCache)
            {
                foreach (var renderer in m_meshRenderCache.MeshRenderers)
                {
                    if (renderer)
                    {
                        LibertySceneManager.EnableLightmapIndex(renderer.lightmapIndex);
                    }
                }
            }
        }

        public void RemoveLightmapIndices()
        {
            if (m_meshRenderCache)
            {
                foreach (var renderer in m_meshRenderCache.MeshRenderers)
                {
                    if (renderer)
                    {
                        LibertySceneManager.DisableLightmapIndex(renderer.lightmapIndex);
                    }
                }
            }
        }

        public void OnCrash()
        {
            if (m_LoadedPrefab)
            {
                var destructibleList = LibertySceneManager.instance.GetComponentCachList;
                m_LoadedPrefab.GetComponentsInChildren<Destructible>(true, destructibleList);
                if (destructibleList != null)
                {
                    foreach (var destructible in destructibleList)
                    {
                        destructible.enabled = false;
                    }
                }
            }
        }

        public bool IsHide { get; set; }

        public bool OnShow(Transform parent, Action<GameObject> callBack = null)
        {
            IsHide = false;
            beforeShow?.Invoke(this);
            if (m_LoadedPrefab == null)
            {
                var path = GetPrefabPath();
                ResObjectCacheManager.Load(path, (go) =>
                {
                    if (!IsHide)
                    {
                        m_LoadedPrefab = go;
                        m_LoadedPrefab.transform.SetParent(parent);


                        if (LibertySceneManager.hasSceneRootOffset)
                        {
                            m_LoadedPrefab.transform.position = Position + LibertySceneManager.sceneRootOffset;
                        }
                        else
                        {
                            m_LoadedPrefab.transform.position = Position;
                        }
                        m_LoadedPrefab.transform.eulerAngles = Rotation;
                        m_LoadedPrefab.transform.localScale = Size;

                        afterShow?.Invoke(this,go);
                        if (!SurvivorManager.IsInGame)
                        {
                            var rigidBody = m_LoadedPrefab.GetComponent<Rigidbody>();
                            if (rigidBody != null)
                            {
                                // rigidBody.isKinematic = false;
                                rigidBody.velocity = Vector3.zero; // 重置线性速度
                                rigidBody.angularVelocity = Vector3.zero; // 重置角速度
                            }

                            var destructibleList = LibertySceneManager.instance.GetComponentCachList;
                            m_LoadedPrefab.GetComponentsInChildren<Destructible>(true, destructibleList);
                            if (destructibleList != null)
                            {
                                foreach (var destructible in destructibleList)
                                {
                                    destructible.enabled = true;
                                    destructible.CurrentHitPoints = destructible.TotalHitPoints;
                                }
                            }
                            SetFarGameObjectMatrix[] setFarGameObjectMatrices = m_LoadedPrefab.GetComponentsInChildren<SetFarGameObjectMatrix>();
                            var playerCamera = LibertyAIUtils.PlayerController?.cameraController?.playerCamera;
                            foreach (var setFarGameObjectMatrix in setFarGameObjectMatrices)
                            {

                                setFarGameObjectMatrix.SaveAllData(playerCamera);
                            }

                        }

                        SetLightmap();

                        callBack?.Invoke(m_LoadedPrefab);
                    }
                    else
                    {
                        ResObjectCacheManager.UnLoad(GetPrefabPath(), go);
                        m_LoadedPrefab = null;
                    }

                });
                return true;
            }
            afterShow?.Invoke(this,m_LoadedPrefab);
            callBack?.Invoke(null);
            return false;
        }

        /// <summary>
        /// 设置光照贴图
        /// </summary>
        private void SetLightmap()
        {
            m_meshRenderCache = m_LoadedPrefab.GetComponent<PrefabMeshRenderCache>();
            if (!m_meshRenderCache) return;

            for (int i = m_MeshRendererDataStartIndex; i < m_MeshRendererDataStartIndex + m_MeshRendererDataCount; i++)
            {
                var meshRendererData = data.MeshRendererDataList[i];
                var index = meshRendererData.renderIndex;
                if (index >= m_meshRenderCache.MeshRenderers.Count)
                {
                    index = m_meshRenderCache.MeshRenderers.Count - 1;
                }
                var renderer = m_meshRenderCache.MeshRenderers[index];
                if (!renderer) continue;

                renderer.lightmapIndex = meshRendererData.lightmapIndex;
                renderer.lightmapScaleOffset = meshRendererData.lightmapScaleOffset;
                //renderer.scaleInLightmap = meshRendererData.scaleInLightmap;

                SetReflectionProbe(renderer);
            }
        }

        /// <summary>
        /// 设置反射探针
        /// </summary>
        /// <param name="renderer"></param>
        private static void SetReflectionProbe(MeshRenderer renderer)
        {
            if (renderer.reflectionProbeUsage == ReflectionProbeUsage.Off) 
                return;

            var result = new List<ReflectionProbeBlendInfo>();
            renderer.GetClosestReflectionProbes(result);
            if (result.IsNotEmpty())
            {
                // 目前只有银行场景需要反射探针，内城房间在LightMapApply中处理

                var info = result[0];
                var probe = info.probe;
                var probeTransform = probe.transform;

                var propertyBlock = new MaterialPropertyBlock();
                renderer.GetPropertyBlock(propertyBlock);
                var probePosition = probeTransform.position;
                var position = new Vector4
                {
                    x = probePosition.x,
                    y = probePosition.y,
                    z = probePosition.z,
                    w = info.weight
                };
                propertyBlock.SetVector(LightMapApply.PROBE_POSITION_PROPERTY_ID, position);
                propertyBlock.SetVector(LightMapApply.PROBE_BOXSIZE_PROPERTY_ID, probe.size);
                propertyBlock.SetVector(LightMapApply.PROBE_BOXOFFSET_PROPERTY_ID, probe.center);
                var rotation = Matrix4x4.TRS(probePosition,
                    Quaternion.Inverse(probeTransform.rotation), Vector3.one);
                propertyBlock.SetMatrix(LightMapApply.PROBE_ROTATION_PROPERTY_ID, rotation);
                var baker = probe.GetComponent<HReflectionProbeBakeRotated>();
                propertyBlock.SetFloat(LightMapApply.PROBE_BOXSPHERE_RADIUS_PROPERTY_ID, baker?.sphereRadius ?? 0);
                renderer.SetPropertyBlock(propertyBlock);
            }
        }

        #endregion

#if UNITY_EDITOR

        [BlackList]
        public void Generate(Transform parent, bool isStatic = false)
        {
#if false
            var o = AssetDatabase.LoadAssetAtPath<GameObject>(GetPrefabPath());
            if (o == null)
            {
                return;
            }
            var prefab = Object.Instantiate(o);
            var sdb = prefab.AddComponent<ScceneDataBind>();
            sdb.Index = m_Index;
            var objectBinder = prefab.GetComponent<SceneObjectBinder>();
            if (objectBinder && objectBinder.ObjectType == SceneObjType.Static)
            {
                isStatic = true;
            }

            if (isStatic)
            {
                sdb.ObjType = SceneObjType.Static;
            }

            prefab.transform.position = m_Position;
            prefab.transform.localScale = m_Size;
            prefab.transform.eulerAngles = m_Rotation;
            prefab.name = prefab.name;
            prefab.transform.SetParent(parent);


            PrefabMeshRenderCache meshRenderCache = prefab.GetComponent<PrefabMeshRenderCache>();
            if (meshRenderCache)
            {
                for (int i = 0; i < meshRenderCache.MeshRenderers.Count; i++)
                {
                    if (i > m_meshRendererDatas.Count - 1)
                    {
                        break;
                    }
                    MeshRenderer renderer = meshRenderCache.MeshRenderers[i];
                    renderer.lightmapIndex = m_meshRendererDatas[i].lightmapIndex;
                    renderer.lightmapScaleOffset = m_meshRendererDatas[i].lightmapScaleOffset;
                }
            }

            LightMapApply lightMapApply = prefab.AddComponent<LightMapApply>();
            lightMapApply.MeshRenderCache = meshRenderCache;
            lightMapApply.MeshRendererDatas = new List<MeshRendererData>();
            lightMapApply.MeshRendererDatas.AddRange(m_meshRendererDatas);
#endif
        }
#endif
        }
    
}
